home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / rf5c68.c < prev    next >
C/C++ Source or Header  |  2000-04-04  |  7KB  |  270 lines

  1. /*********************************************************/
  2. /*    ricoh RF5C68(or clone) PCM controller              */
  3. /*********************************************************/
  4.  
  5. #include "driver.h"
  6. #include <math.h>
  7.  
  8. #define PCM_NORMALIZE
  9.  
  10. enum
  11. {
  12.     RF_L_PAN = 0, RF_R_PAN = 1, RF_LR_PAN = 2
  13. };
  14.  
  15. static RF5C68PCM    rpcm;
  16. static int  reg_port;
  17. static int emulation_rate;
  18.  
  19. static int buffer_len;
  20. static int stream;
  21.  
  22. //static unsigned char pcmbuf[0x10000];
  23. static unsigned char *pcmbuf=NULL;
  24.  
  25. static struct RF5C68interface *intf;
  26.  
  27. static unsigned char wreg[0x10]; /* write data */
  28.  
  29. #define   BASE_SHIFT    (11+4)
  30.  
  31. #define    RF_ON     (1<<0)
  32. #define    RF_START  (1<<1)
  33.  
  34.  
  35. static void RF5C68Update( int num, INT16 **buffer, int length );
  36.  
  37. /************************************************/
  38. /*    RF5C68 start                              */
  39. /************************************************/
  40. int RF5C68_sh_start( const struct MachineSound *msound )
  41. {
  42.     int i;
  43.     int rate = Machine->sample_rate;
  44.     struct RF5C68interface *inintf = msound->sound_interface;
  45.  
  46.     if (Machine->sample_rate == 0) return 0;
  47.  
  48.     if(pcmbuf==NULL) pcmbuf=(unsigned char *)malloc(0x10000);
  49.     if(pcmbuf==NULL) return 1;
  50.  
  51.     intf = inintf;
  52.     buffer_len = rate / Machine->drv->frames_per_second;
  53.     emulation_rate = buffer_len * Machine->drv->frames_per_second;
  54.  
  55.     rpcm.clock = intf->clock;
  56.     for( i = 0; i < RF5C68_PCM_MAX; i++ )
  57.     {
  58.         rpcm.env[i] = 0;
  59.         rpcm.pan[i] = 0;
  60.         rpcm.start[i] = 0;
  61.         rpcm.step[i] = 0;
  62.         rpcm.flag[i] = 0;
  63.     }
  64.     for( i = 0; i < 0x10; i++ )  wreg[i] = 0;
  65.     reg_port = 0;
  66.  
  67.     {
  68.         char buf[LR_PAN][40];
  69.         const char *name[LR_PAN];
  70.         int  vol[2];
  71.         name[0] = buf[0];
  72.         name[1] = buf[1];
  73.         sprintf( buf[0], "%s Left", sound_name(msound) );
  74.         sprintf( buf[1], "%s Right", sound_name(msound) );
  75.         vol[0] = (MIXER_PAN_LEFT<<8)  | (intf->volume&0xff);
  76.         vol[1] = (MIXER_PAN_RIGHT<<8) | (intf->volume&0xff);
  77.  
  78.         stream = stream_init_multi( RF_LR_PAN, name, vol, rate, 0, RF5C68Update );
  79.         if(stream == -1) return 1;
  80.     }
  81.     return 0;
  82. }
  83.  
  84. /************************************************/
  85. /*    RF5C68 stop                               */
  86. /************************************************/
  87. void RF5C68_sh_stop( void )
  88. {
  89.     if(pcmbuf!=NULL) free(pcmbuf);
  90.     pcmbuf=NULL;
  91. }
  92.  
  93. /************************************************/
  94. /*    RF5C68 update                             */
  95. /************************************************/
  96.  
  97. INLINE int ILimit(int v, int max, int min) { return v > max ? max : (v < min ? min : v); }
  98.  
  99. static void RF5C68Update( int num, INT16 **buffer, int length )
  100. {
  101.     int i, j, tmp;
  102.     unsigned int addr, old_addr;
  103.     signed int ld, rd;
  104.     INT16  *datap[2];
  105.  
  106.     datap[RF_L_PAN] = buffer[0];
  107.     datap[RF_R_PAN] = buffer[1];
  108.  
  109.     memset( datap[RF_L_PAN], 0x00, length * sizeof(INT16) );
  110.     memset( datap[RF_R_PAN], 0x00, length * sizeof(INT16) );
  111.  
  112.     for( i = 0; i < RF5C68_PCM_MAX; i++ )
  113.     {
  114.         if( (rpcm.flag[i]&(RF_START|RF_ON)) == (RF_START|RF_ON) )
  115.         {
  116.             /**** PCM setup ****/
  117.             addr = (rpcm.addr[i]>>BASE_SHIFT)&0xffff;
  118.             ld = (rpcm.pan[i]&0x0f);
  119.             rd = ((rpcm.pan[i]>>4)&0x0f);
  120.             /*       cen = (ld + rd) / 4; */
  121.             /*       ld = (rpcm.env[i]&0xff) * (ld + cen); */
  122.             /*       rd = (rpcm.env[i]&0xff) * (rd + cen); */
  123.             ld = (rpcm.env[i]&0xff) * ld;
  124.             rd = (rpcm.env[i]&0xff) * rd;
  125.  
  126.             for( j = 0; j < length; j++ )
  127.             {
  128.                 old_addr = addr;
  129.                 addr = (rpcm.addr[i]>>BASE_SHIFT)&0xffff;
  130.                 for(; old_addr <= addr; old_addr++ )
  131.                 {
  132.                     /**** PCM end check ****/
  133.                     if( (((unsigned int)pcmbuf[old_addr])&0x00ff) == (unsigned int)0x00ff )
  134.                     {
  135.                         rpcm.addr[i] = rpcm.loop[i] + ((addr - old_addr)<<BASE_SHIFT);
  136.                         addr = (rpcm.addr[i]>>BASE_SHIFT)&0xffff;
  137.                         /**** PCM loop check ****/
  138.                         if( (((unsigned int)pcmbuf[addr])&0x00ff) == (unsigned int)0x00ff )    // this causes looping problems
  139.                         {
  140.                             rpcm.flag[i] = 0;
  141.                             break;
  142.                         }
  143.                         else
  144.                         {
  145.                             old_addr = addr;
  146.                         }
  147.                     }
  148. #ifdef PCM_NORMALIZE
  149.                     tmp = rpcm.pcmd[i];
  150.                     rpcm.pcmd[i] = (pcmbuf[old_addr]&0x7f) * (-1 + (2 * ((pcmbuf[old_addr]>>7)&0x01)));
  151.                     rpcm.pcma[i] = (tmp - rpcm.pcmd[i]) / 2;
  152.                     rpcm.pcmd[i] += rpcm.pcma[i];
  153. #endif
  154.                 }
  155.                 rpcm.addr[i] += rpcm.step[i];
  156.                 if( !rpcm.flag[i] )  break; /* skip PCM */
  157. #ifndef PCM_NORMALIZE
  158.                 if( pcmbuf[addr]&0x80 )
  159.                 {
  160.                     rpcm.pcmx[0][i] = ((signed int)(pcmbuf[addr]&0x7f))*ld;
  161.                     rpcm.pcmx[1][i] = ((signed int)(pcmbuf[addr]&0x7f))*rd;
  162.                 }
  163.                 else
  164.                 {
  165.                     rpcm.pcmx[0][i] = ((signed int)(-(pcmbuf[addr]&0x7f)))*ld;
  166.                     rpcm.pcmx[1][i] = ((signed int)(-(pcmbuf[addr]&0x7f)))*rd;
  167.                 }
  168. #else
  169.                 rpcm.pcmx[0][i] = rpcm.pcmd[i] * ld;
  170.                 rpcm.pcmx[1][i] = rpcm.pcmd[i] * rd;
  171. #endif
  172.                 *(datap[RF_L_PAN] + j) = ILimit( ((int)*(datap[RF_L_PAN] + j) + ((rpcm.pcmx[0][i])>>4)), 32767, -32768 );
  173.                 *(datap[RF_R_PAN] + j) = ILimit( ((int)*(datap[RF_R_PAN] + j) + ((rpcm.pcmx[1][i])>>4)), 32767, -32768 );
  174.             }
  175.         }
  176.     }
  177. }
  178.  
  179. /************************************************/
  180. /*    RF5C68 write register                     */
  181. /************************************************/
  182. WRITE_HANDLER( RF5C68_reg_w )
  183. {
  184.     int  i;
  185.     int  val;
  186.  
  187.     wreg[offset] = data;            /* stock write data */
  188.     /**** set PCM registers ****/
  189.     if( (wreg[0x07]&0x40) )  reg_port = wreg[0x07]&0x07;    /* select port # */
  190.  
  191.     switch( offset )
  192.     {
  193.         case 0x00:
  194.             rpcm.env[reg_port] = data;        /* set env. */
  195.             break;
  196.         case 0x01:
  197.             rpcm.pan[reg_port] = data;        /* set pan */
  198.             break;
  199.         case 0x02:
  200.         case 0x03:
  201.             /**** address step ****/
  202.             val = (((((int)wreg[0x03])<<8)&0xff00) | (((int)wreg[0x02])&0x00ff));
  203.             rpcm.step[reg_port] = (int)(
  204.             (
  205.             ( 28456.0 / (float)emulation_rate ) *
  206.             ( val / (float)(0x0800) ) *
  207.             (rpcm.clock / 8000000.0) *
  208.             (1<<BASE_SHIFT)
  209.             )
  210.             );
  211.             break;
  212.         case 0x04:
  213.         case 0x05:
  214.             /**** loop address ****/
  215.             rpcm.loop[reg_port] = (((((unsigned int)wreg[0x05])<<8)&0xff00)|(((unsigned int)wreg[0x04])&0x00ff))<<(BASE_SHIFT);
  216.             break;
  217.         case 0x06:
  218.             /**** start address ****/
  219.             rpcm.start[reg_port] = (((unsigned int)wreg[0x06])&0x00ff)<<(BASE_SHIFT + 8);
  220.             rpcm.addr[reg_port] = rpcm.start[reg_port];
  221.             break;
  222.         case 0x07:
  223.             if( (data&0xc0) == 0xc0 )
  224.             {
  225.                 i = data&0x07;        /* register port */
  226.                 rpcm.pcmx[0][i] = 0;
  227.                 rpcm.pcmx[1][i] = 0;
  228.                 rpcm.flag[i] |= RF_START;
  229.             }
  230.             break;
  231.  
  232.         case 0x08:
  233.             /**** pcm on/off ****/
  234.             for( i = 0; i < RF5C68_PCM_MAX; i++ )
  235.             {
  236.                 if( !(data&(1<<i)) )
  237.                 {
  238.                     rpcm.flag[i] |= RF_ON;    /* PCM on */
  239.                 }
  240.                 else
  241.                 {
  242.                     rpcm.flag[i] &= ~(RF_ON); /* PCM off */
  243.                 }
  244.             }
  245.             break;
  246.     }
  247. }
  248.  
  249. /************************************************/
  250. /*    RF5C68 read memory                        */
  251. /************************************************/
  252. READ_HANDLER( RF5C68_r )
  253. {
  254.     unsigned int  bank;
  255.     bank = ((unsigned int)(wreg[0x07]&0x0f))<<(8+4);
  256.     return pcmbuf[bank + offset];
  257. }
  258. /************************************************/
  259. /*    RF5C68 write memory                       */
  260. /************************************************/
  261. WRITE_HANDLER( RF5C68_w )
  262. {
  263.     unsigned int  bank;
  264.     bank = ((unsigned int)(wreg[0x07]&0x0f))<<(8+4);
  265.     pcmbuf[bank + offset] = data;
  266. }
  267.  
  268.  
  269. /**************** end of file ****************/
  270.